import {
  IPlank,
  OrderState as EOrderState,
  OrderState as ESource,
} from '@/types';
import { composeModels, genModelId } from '@/utils/model';
import { defaults, isEmpty, isNil, negate } from 'lodash-es';
import { filterBomGroupsByCategory } from '../utils/filterBomGroupsByCategory';
import { getDataConfig } from './data-config';
import * as store from './store';
export { ESource as EBomSource, EOrderState };
export { IListParams as IBomListParams };

// --- order ---

interface IListParams {
  source?: ESource;
  orderState?: EOrderState;
  pageNum?: number;
  pageSize?: number;
}
async function getOriginList(params?: IListParams) {
  const { orderState, pageNum, pageSize } = defaults(params, {
    pageNum: 1,
    pageSize: 10,
  });
  // 获取板件数据
  const res = await Manycore.Integration.FOP.findOrdersAsync({
    // orderState: source,
    orderState,
    start: (pageNum - 1) * pageSize,
    num: pageSize,
  });
  const orders = res.result;
  const { totalCount: total, hasMore } = res;
  // console.log({ orders });
  const promises = orders.map(async (order) => {
    const { orderId } = order;
    const plankList = (
      await Manycore.Integration.Bom.findPlankListAsync({ orderId })
    ).result;
    // console.log({ orderId, plankList });
    return { order, plankList, total };
  });
  const data = await Promise.all(promises);
  return { data, total, hasMore };
}

async function getOrderList(params: IListParams) {
  const res = await getOriginList(params);
  const { data: list, total, hasMore } = res;
  // console.log({ results });
  const data = list.map((item) => {
    const { order: order_2, plankList: plankList_1 } = item;
    return {
      id: order_2.orderId,
      name: order_2.orderName,
      date: order_2.placeTime,
      data: plankList_1,
    };
  });
  return { data, total, hasMore };
}
const getDesignOrderList = Manycore.Integration.FOP.getDesignOrderListAsync;
const getOrder = Manycore.Integration.FOP.getOrderAsync;
const findOrders = Manycore.Integration.FOP.findOrdersAsync;
async function getDesignDetail(params: { designId: string }) {
  const { designId } = params;
  const orders = await getDesignOrderList({ designId });
  const [order] = orders;
  if (!order) return;
  const { orderId } = order;
  const orderResult = (await findOrders({ orderIds: [orderId] })).result[0];
  if (!orderResult) return;
  const { designName } = orderResult;
  return { designId, designName };
}
type IIsNonNullable = <T>(value: T) => value is NonNullable<T>;
const IsNonNullable = negate(isNil) as IIsNonNullable;
async function getDesignList(params: {
  designIds: string[];
}): Promise<{ designId: string; designName: string }[]> {
  const { designIds } = params;
  return (
    await Promise.all(
      designIds.map(async (designId) => {
        const detail = await bomApi.getDesignDetail({ designId });
        if (!detail) return;
        return detail;
      }),
    )
  ).filter(IsNonNullable);
}

// --- plank ---

async function getDesignPlanks(params: {
  designId: string;
}): Promise<IPlank[]> {
  const orders = await Manycore.Integration.FOP.getDesignOrderListAsync(params);
  if (isEmpty(orders)) {
    return [];
  }
  const orderIds = orders.map(({ orderId }) => orderId);
  const { result: planks } = await Manycore.Integration.Bom.findPlankListAsync({
    orderIds,
  });
  // Manycore.Integration.Bom.findFinishedProductsAsync({orderIds:['3FO4K4VWSX6W']})
  const { finishedProducts } =
    await Manycore.Integration.Bom.findFinishedProductsAsync({ orderIds });
  const { moldings } = await Manycore.Integration.Bom.findMoldingsAsync({
    orderIds,
  });
  const { groups } = await Manycore.Integration.Bom.findGroupsByOrderIdAsync({
    orderIds,
  });
  const { categorys, excludeModelNames } = await getDataConfig();
  const filteredGroups = filterBomGroupsByCategory(groups, categorys);

  // finishedProducts[0].modelId
  // moldings[0].modelId
  // groups[0].modelId

  const newResult: any[] = ([] as any[])
    .concat(
      planks,
      composeModels([...finishedProducts, ...filteredGroups].map(genModelId)),
      composeModels(moldings),
    )
    .filter((item) => {
      return !excludeModelNames.includes(item.name);
    });
  return newResult;
}

async function getMergePlankList(params: IListParams) {
  const { pageNum, pageSize } = defaults(params, {
    pageNum: 1,
    pageSize: 10,
  });

  // 获取合批数据
  const res = await Manycore.Integration.FOP.findMergeTasksAsync({
    start: (pageNum - 1) * pageSize,
    num: pageSize,
  });
  const merges = res.result;
  const { totalCount: total, hasMore } = res;
  const promises = merges.map(async (merge) => {
    const { mergeId } = merge;
    const plankList = (
      await Manycore.Integration.Bom.getPlankListAsync({
        // @ts-ignore
        mergeIds: [mergeId].join(),
      })
    ).result;
    return { merge, plankList, total };
  });
  const data = await Promise.all(promises);

  const list = data.map((item) => {
    return {
      id: item.merge.mergeId,
      name: item.merge.mergeName,
      date: 0,
      data: item.plankList,
    };
  });

  return { data: list, total, hasMore };
}

export interface IPlankListParams {
  orderId?: string;
  orderIds?: string[];
  mergeId?: string;
}
const getPlankList = async (params: IPlankListParams) => {
  const { mergeId, orderId, orderIds } = params;

  return await Manycore.Integration.Bom.findPlankListAsync({
    // @ts-ignore
    orderId,
    orderIds,
    // @ts-ignore
    mergeIds: mergeId,
  });
};
const deletePlanks = Manycore.Integration.Bom.deletePlanksAsync;

// --- mark-plank ---

namespace MarkPlank {
  export enum StoreKey {
    Planks = 'mark-plank/planks',
    ExtraInfos = 'mark-plank/extra-infos',
  }
}

function genKey(keys: string[]) {
  return keys.join('/');
}
function toPath(obj: Record<string, any>) {
  return Object.entries(obj).map((item) => {
    return item.join('/');
  });
}

interface IMarkPlankBaseParams {
  designId: string;
}
interface IUpdateMarkedPlanksParams extends IMarkPlankBaseParams {
  planks: IPlank[];
}
async function updateMarkedPlankList(
  params: IUpdateMarkedPlanksParams,
): Promise<void> {
  const { planks, designId } = params;

  store.setItem({
    key: genKey([MarkPlank.StoreKey.Planks, ...toPath({ designId })]),
    value: planks,
  });
}
interface IGetMarkedPlanksParams extends IMarkPlankBaseParams {}
async function getMarkedPlankList(
  params: IGetMarkedPlanksParams,
): Promise<IPlank[]> {
  const { designId } = params;
  return (
    (await store.getItem({
      key: genKey([MarkPlank.StoreKey.Planks, ...toPath({ designId })]),
    })) || []
  );
}

interface IMarkedPlanKPlankExtraInfo {
  modelId: string;
  updateTime: number;
}
async function updateMarkedPlankExtraInfoList(
  params: IUpdateMarkedPlanksParams,
) {
  const { designId, planks } = params;
  const modelIds = planks.map((plank) => plank.modelId);
  const newInfos: IMarkedPlanKPlankExtraInfo[] = modelIds.map((modelId) => ({
    modelId,
    updateTime: Date.now(),
  }));
  const oldInfos = await getMarkedPlankExtraInfoList(params);
  const unChangedInfos = oldInfos.filter(
    (info) => !modelIds.includes(info.modelId),
  );
  const infos = unChangedInfos.concat(newInfos);
  await store.setItem({
    key: genKey([MarkPlank.StoreKey.ExtraInfos, ...toPath({ designId })]),
    value: infos,
  });
}
async function getMarkedPlankExtraInfoList(params: IGetMarkedPlanksParams) {
  const { designId } = params;
  const extraInfos = await store.getItem<IMarkedPlanKPlankExtraInfo[]>({
    key: genKey([MarkPlank.StoreKey.ExtraInfos, ...toPath({ designId })]),
  });
  return extraInfos || [];
}

export const bomApi = {
  getDesignDetail,
  getDesignList,

  getOrderList,
  getDesignOrderList,

  getMergePlankList,
  getPlankList,
  deletePlanks,
  getDesignPlanks,

  updateMarkedPlankList,
  getMarkedPlankList,
  updateMarkedPlankExtraInfoList,
  getMarkedPlankExtraInfoList,
};
